﻿using Max.PH5_2103A.Shopping.TEntityFrame.DTO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Max.PH5_2103A.Shopping.TEntityFrame.API.Controllers
{

    /*
     * 一、安装Redis
     * 直接解压，并安装成Windows服务（电脑启动、redis也会启动）
     * 
     * 二、在VS中使用Redis
     * 1、安装包 CsRedisCore
     * 2、连接到Redis服务器
     * 
     * **/

    /// <summary>
    /// 电商购物车API控制器接口
    /// </summary>
    [Route("car")]
    [ApiController]
    public class ShoppingCarController : ControllerBase
    {
        //创建redis客户端连接对象
        CSRedis.CSRedisClient _redisClient = new CSRedis.CSRedisClient("127.0.0.1:6390");
        NLog.Logger _log = NLog.LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 添加到购物车
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddCar(ShoppingCarDto dto)
        {
            string key = dto.MemberId.ToString(); //表示在redis中唯一的标识，表示是你的购物车
            string field = dto.SkuId.ToString();//哈希表中唯一的


            //判断是否是同样的商品
            //如果是：则商品的数量相加

            //从你的购物车中，获取要添加的商品
            var m = _redisClient.HGet<ShoppingCarDto>(key, field);
            if (m == null)
            {
                //说明你的购物车，原来没有这个商品，则可以直接放入
                _redisClient.HSet(key, field, dto);
            }
            else
            {
                //你的购物车，之前有这个商品，那么购买商品的数量累加
                m.Number += dto.Number;
                //累加完后，要更新到你的购物车中
                _redisClient.HSet(key, field, m);
            }

            return Ok();
        }


        /// <summary>
        /// 获取购物车
        /// </summary>
        /// <param name="memberId"></param>        
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetCar(string memberId)
        {
            ResponseResultDto response = new();

            string key = memberId;
            var data = _redisClient.HGetAll<ShoppingCarDto>(key);

            //这样拿到的数据，不是列表，不好直接在前台显示。所以需要处理。 //2023/9/19
            //处理字典
            List<ShoppingCarDto> list = new(); //字典的数据是有多条，则是集合，所以新new一个集合，用来保存字典的value
            foreach (var item in data)
            {
                list.Add(item.Value);
            }

            #region 20230921 根据店铺来显示
            //在数据列表中，通过去重查询店铺这一列，获取店铺名称
            var storeNames = list.DistinctBy(x => x.StoreName).Select(x => x.StoreName);

            //根据获取店铺名称，再去查询该店铺下面有哪些商品
            var q = from a in storeNames
                    select new
                    {
                        StoreName = a,
                        Products = list.Where(x => x.StoreName.Equals(a)).ToList()
                    };

            #endregion


            response.Data = q;

            return Ok(response);
        }


        /// <summary>
        /// 删除购物车(单删除和批量删除)
        /// </summary>
        /// <param name="memberId">会员id</param>
        /// <param name="skuIds">要删除的商品id（可以删除多个商品）</param>
        /// <returns></returns>
        [HttpDelete]
        public IActionResult DeleteCar(string memberId, string[] skuIds)
        {
            string key = memberId;

            _redisClient.HDel(key, skuIds);


            _log.Info($"成功从购物车<{key}>中删除一个商品<{string.Join(",",skuIds)}>");

            return Ok();
        }

        /// <summary>
        /// 修改购物车（只修改你购买的商品数量）
        /// </summary>
        /// <returns></returns>
        [HttpPut]
        public IActionResult UpdateCar(ShoppingCarDto dto)
        {
            string key = dto.MemberId.ToString();
            string field = dto.SkuId.ToString();

            var d = _redisClient.HGet<ShoppingCarDto>(key, field);  //先要拿出来：类型修电脑配件，把配件从电脑整机中取下来
            if (d != null)
            {
                d.Number = dto.Number;  //修改一个数量
                _redisClient.HSet(key, field, d); //重新放回去：更新redis
            }

            return Ok();
        }
    }




    #region Redis Hash使用讲解


    /// <summary>
    /// 购物车
    /// </summary>
    [Route("car")]
    [ApiController]
    class _ShoppingCarController : ControllerBase
    {
        /*
         * Redis支持5种数据类型：string,hash,list,set,zset
         * 
         * 现在要存放的是购物车的信息
         * 购物车：是指存放每个登录的用户，他想购买的商品。
         * 那么说明：会有多种商品，每种商品又可能有多个数量
         * 
         * Hash：Key/Value（无序、取值快、是根据key直接取）
         * 在购物车中，每个会员所存放的商品的种类，应该是唯一的，但数量不是1。
         * 所以hash的key，就可以用商品的标识
         * 
         * Redis：也是Key/Value
         * Redis中的key,是指具体哪一个用户的标识。命名(全都小写)可以用：member_具体id(这个id是数据表中，会员的id)
         * Redis中具体操作：Get获取数据，Set 是设置数据
         * **/

        CSRedis.CSRedisClient _client = new CSRedis.CSRedisClient("127.0.0.1:6390"); //127.0.0.1是redis的服务器地址，默认端口是6379

        /// <summary>
        /// 添加购物车
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult TestInsert()
        {
            var data = new TestCarModel
            {
                MemberId = Guid.NewGuid(),
                ProductId = Guid.NewGuid(),
                ProductName = "商品名称",
                ProductNumber = 1,
                ProductPrice = 100
            };

            string key = $"member_{data.MemberId.ToString().ToLower()}"; //redis中，大小写敏感。所以统一用小写
            string field = data.ProductId.ToString().ToLower();
            _client.HSet(key, field, data);  //把数据存入到redis，用Hash格式

            //把数据放到缓存redis中。默认是永久的。
            _client.Expire(key, 2 * 60 * 60);//为这一个key设置过期时间

            var m = _client.HGet<TestCarModel>(key, field); //用hash格式，把redis中的数据取出来

            if (m != null)
            {
                //其它处理
            }
            return Ok();
        }

    }

    class TestCarModel
    {
        public Guid MemberId { get; set; }
        public Guid ProductId { get; set; }
        public string ProductName { get; set; }
        public decimal ProductPrice { get; set; }
        public int ProductNumber { get; set; }

    }

    #endregion
}
